/**
 *	The NeuroCoSA Toolkit
 *	Copyright (C) 2003-6 Stuart Meikle.
 *
 *	This is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU Lesser General Public
 *	License as published by the Free Software Foundation; either
 *	version 2.1 of the License, or (at your option) any later version.
 *
 *	This library is distributed in the hope that it will be useful,
 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *	Lesser General Public License for more details.
 *
 * @author	Stuart Meikle
 * @version	2006-halloween(mk2)
 * @license	LGPL
 */
package org.stumeikle.NeuroCoSA;


import java.util.*;
import java.awt.*;
import java.awt.event.*;
import java.lang.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.*;
import javax.swing.event.*;


/**
 * Bimode neuron - a neuron which has 2 modes: learning and driving
 *
 */
public class	BiModeNeuron extends Neuron
{
    public     static final int mode_learning = 0;
    public     static final int mode_driving  = 1;
    private    int		iMode; /** is the neuron is mode learning or mode driving ? */
    protected  double		iLearnSig, iDriveSig;

    /**
     * Constructor. 
     * @param list of lobes. This neuron is permitted to connect its output to 
     * neurons in these lobes
     */
    public BiModeNeuron( Layer l)
    { 
	super(l);
	doConstruct();
    }

    private	void	doConstruct()
    {
    	iMode=mode_learning;
	iLearnSig=0.0;
	iDriveSig=0.0;
    }

    public int		getMode()
    {  return iMode; }

    /** sets the neuron into learning mode */
    public void		setModeLearning()
    { iMode = mode_learning; 
    }

    /** sets the neuron to driving mode */
    public void		setModeDriving()
    { iMode = mode_driving; }


//ADD update....

    /** routines which can/shoudl be called by classes derived from bimodeneuron
     */
    public void		setLearnSigStr( double s )
    {
        iLearnSig=s;
    }
    /** routines which can/shoudl be called by classes derived from bimodeneuron
     */
    public void		setDriveSigStr( double s )
    {
        iDriveSig=s;
    }
    /** routines which can/shoudl be called by classes derived from bimodeneuron
     */
    public double 	getLearnSigStr()
    { return iLearnSig;  }
    /** routines which can/shoudl be called by classes derived from bimodeneuron
     */
    public double 	getDriveSigStr()
    { return iDriveSig; }
    
    /** call this at the start of create vesicle package
     *  routines which can/shoudl be called by classes derived from bimodeneuron
     */
    public void	  	resetModeVars()
    { 
      iDriveSig=iLearnSig= 0.0; 
      iMode=mode_learning;
    }

    /** routines which can/shoudl be called by classes derived from bimodeneuron
     */
    public boolean	updateLearnSig( double d )
    {
    	boolean	retval = false;
    
        if (iLearnSig>=0.0 && d>iLearnSig)
	{
		iLearnSig=d;
		retval = true;
	}
	else if (iLearnSig<0.0 && d < iLearnSig)
	{
		iLearnSig=d;
		retval = true;
	}
	return 	retval;
    }
    
    /** routines which can/shoudl be called by classes derived from bimodeneuron
     */
    public boolean	updateDriveSig( double d )
    {
    	boolean	retval = false;
    
	if (iDriveSig>=0.0 && d>iDriveSig)
	{	iDriveSig=d;
		retval = true;
	}
	else if (iDriveSig<0.0 && d < iDriveSig)
	{
		iDriveSig=d;
		retval = true;
	}
	
	return retval;
    }
        
    /** call this at the end of create vesicle package
     */
    public double 	setModeGetSigStr()
    {
    	double	ls_mag, ds_mag;
	
	ls_mag = iLearnSig;	if (ls_mag<0)	ls_mag*=-1.0;
	ds_mag = iDriveSig;	if (ds_mag<0)	ds_mag*=-1.0;
	
	if (ls_mag == 0.0 && ds_mag ==0.0)
	{
	    iMode = mode_learning;
	    return 0.0;
	}
	else
	{
 	    if (ls_mag>ds_mag) 
	    {
	        iMode=mode_learning;
	        return iLearnSig;
	    }else
	    {
	        iMode=mode_driving;
	    
	        //20050824 - report the driving mode of this neuron to the brain change monitor
// 	        iParent.notifySpecificChange( this, bcm_neuron_driving );
	        return iDriveSig;
	    }
	}
    }

    /**
     *  local version of create vesicle. ensures that modes and winners are 
     *  reset before the vesicle is created.
     *  specific instances must call setModeGetSigStr() in their implementation of 
     *  create bi mode vesicle
     */
    public final Vesicle	createVesicle( Vesicle v )
    {
	//take control from the layer here and fire if our exemplar matches
	//that of the layer
	Vesicle		retval=null;

	resetModeVars();
	retval = createBiModeVesicle(v);

	//specific instances must call setModeGetSigStr() in their implementation of 
	//create bi mode vesicle	

	return retval;
    }

    protected Vesicle		createBiModeVesicle(Vesicle v)
    {

	// NOTE: BEWARE: if you return NULL from this routine, your neuron
	// will be left in its previous state, no reset to inactive occurs!!!

	System.out.println("*** ERROR, createBiModeVeiscle must be overloaded in class " + this);
	System.out.println("*** Also be sure to call setModeGetSigStr() in createVesicle");
	System.exit(-1);
	return null;
    }

    /** 
     * Called by neuron. Here we check with the synapses to see if they passed a drive
     * signal and if it was successful in beeing the winning drive signal of the other lobe
     * .Here we also try to introduce expectation ...
     */
    protected	void		reviewBehaviour()
    {
    	//Maybe. If we get to the point where the algorithm in SimpleNeuron and
	//Grasping Neuron is repeated then the code can be moved into this base class. 
    
    	//Algo:
	//(1) is the neuron being driven ?
	//(1.5) and does the neuron have control of the output lobe
	//(2) if yes, then start expecting that we enter a learn state
	//    IE start expecting that we will succeed in our action
	//(3) check if the expectation is met
	//(4) if yes, then count the success
	//(5) if no, then count the failure.
	//(6) if the failure is too high then remove the neuron
	//(6.5) although removal is OPTIONAL
	//(7) update the expectation
	
	//Things provided externally:
	//(1) should we track this information at all?
	//(2) is the neuron controlling its output?
	//(3) should we remove the neuron if it is not successful?
	//(4) ... maybe ... the initial value of our expectation time
    }
}
